A Progress Simulator

by Gordon Rahman

grahman@planet.nl


Home

Text To Speech - Pendl

Novice Puzzles - Terra

Slider Controls - Bradbury

Symmetrical Paint - Nally

Programming Style - Brossman

Progress Simulator - Rahman

CD Menus - Sweet

Media File Search - Sweet

Why Liberty BASIC? - Sweet

Submission Guildlines

Newsletter Help

Index

Progress Simulator Combines Features Developed by Others

This progress simulator doesn't bring something new to programming or coding in Liberty Basic. I just combined several features and code from others to realise my progress simulator.

Here is how I got it all together:

While the other simulators are focused on displaying a bar in a window at some preset pace, I concentrated on copying folders.

My simulator can be extended with user selection of the source folder in stead of the fixed default folder that my program uses. The program can also get improved by putting a routine to remove the read only file attribute from each copied file. This is very useful when the program should copy file from a CD.

'Progress simulator
'Gordon Rahman

    dim Finfo$(10,3)			'needed by Brad's function 
    dim FileTree$(2000)		'needed by Brad's function
    MaxEntries = 1999			'needed by Brad's function

    global totalBytes			'LB4 feature

    graphw = 335

'Form created with the help of Freeform 3
'Generated on Nov 19, 2003 at 23:18:37

    DestinationPath$ = "C:\Games\Nieuwe map"

[setupMainWindow]

    '-----Begin main GUI window code

    nomainwin
    WindowWidth = 400
    WindowHeight = 450
    UpperLeftX=int((DisplayWidth-WindowWidth)/2)
    UpperLeftY=int((DisplayHeight-WindowHeight)/2)

    BackgroundColor$ = "buttonface"
    ForegroundColor$ = "black"

    '-----Begin GUI objects code

    TextboxColor$ = "white"

    '
    '-----------\
    'FIRST ARROW >
    '-----------/
                            groupbox #main.groupbox2, "Default Destination Folder", 15, 237, 365, 95
                            groupbox #main.groupbox3, "Status", 15, 237, 365, 95

    textbox #main.textbox1, 30, 272, graphw, 25
    graphicbox #main.graphbox1, 30, 272, graphw, 25
    button #main.button3, "Start", [button3Click], UL, 130, 382, 105, 25
    button #main.button4, "Exit", [exit], UL, 260, 382, 105, 25

    statictext #main.statictext3, "Source Folder", 10, 40, 200, 20
    statictext #main.statictext4, "Destination Folder", 10, 140, 200, 20
    statictext #main.statictext5, "", 10, 60, 385, 30
    statictext #main.statictext6, "", 10, 160, 385, 30
    statictext #main.statictext7, "", 30, 300, 200, 20
    button #main.button8, "Browse", [browse], UL, 260, 302, 105, 25

    '-----End GUI objects code

    open "XCOPY" for window as #main
    print #main, "font ms_sans_serif 0 16"

    '------------\
    'SECOND ARROW >
    '------------/

			print #main.statictext3, "!font arial 14 italic"
    		print #main.statictext4, "!font arial 14 italic"

    print #main, "trapclose [quit]"
    print #main.graphbox1, "fill white"
    print #main.groupbox3, "!hide"
    print #main.graphbox1, "hide"

    print #main.textbox1, DestinationPath$

The window below was created with Freeform. Both day and time stamps at generating are still attached. So there is little more left to add to it. Let's concentrate on the two arrows I placed in the code.

The following part of this snippet gives room for improvement. As stated here the program will use the default directory that Windows uses currently. The variable sPath$ is than used as parameter in the function called Entries.

  
  sPath$ = DefaultDir$ + "\"  'change the default dir (source dir) here

One of the first actions the program does is to measure the size of all the files found in the source folder and all its sub directories. To find the number of files in the source folder and count their sizes I asked at the forum for the API routine to do this. It is good thing that nobody answered my plea, because I found the routine lying inside the LB4 directory. It only states a title "get the size of a folder" and is named "foldersize.bas". I discovered it at Liberty Belle.

At last I used the routine to find all the files in a folder. I combined this with the FILES command (info$(x,1) I found in the help files. Therefore I introduced the variable totalBytes.

The variable totalBytes is reset to zero to begin with and must be a global variable. Global variables can be used (change value) inside functions. Then user function for Entries=FileTree( with 8 parameters) is called for the first time. This function is made by the editor of this Newsletter, Brad Moore as I said before.

  totalBytes = 0
  Entries = FileTree(MaxEntries, 0, 0, sPath$, 24, 1, 1, 1)
  totalBytes = int(totalBytes/1000000)
  #main.statictext7, "Required: " + str$(totalBytes) + " MB"

[main.inputLoop]   'wait here for input event
    wait


[exit]            'Perform action for the button named 'button4'
[quit]           'Same action to End the program
    close #main
    end

This is the end of the main loop of the snippet. What follows is a call to a user DLL to open a "folderdialog window" so to speak. After that there is the routine to actually copy the files from one place to another. And at last the function of Brad Moore.

When we issue the browse button this will trigger this piece of code. This piece of code is wide spread and freeware. I came across it at several places. I only marked the text on two locations where I replaced the standard text. As the routine comes with a lot of remarks, it's not necessary to repeat or shed more light on it.

'--------------------------------------------------------------
[browse]   'Perform action for the button named 'Browse'

'Folders browse I found in Mastering Liberty Basic made by Brent, Alyce, many others
'I have seen this routine at several places
'The following Function is courtesy Lazman (with help from Alyce)
'It opens a system window and allows the use to search for and select a 
'folder, not a file like what is possible with the FILEDIALOG command


BIF.RETURNONLYFSDIRS = 1
BIF.USENEWUI = hexdec("40")

MAX.PATH = 260
crlf$=chr$(13)+chr$(10)

'Create structure for API call
STRUCT BrowseInfo,_
    hWndOwner As Long,_
    pIDLRoot As Long,_
    pszDisplayName As Long,_
    lpszTitle$ As ptr,_
    ulFlags As Long,_
    lpfnCallback As Long,_
    lParam As Long,_
    iImage As Long

    'Set the owner window, optional
    BrowseInfo.hWndOwner.struct = 0

    'Set  up text to display on the dialog:

    txt1$="Select folder for the application." + crlf$
    txt1$=txt1$+DefaultDir$ +" will be added to this folder"

    'Fill the struct item with the text
    BrowseInfo.lpszTitle$.struct = txt1$

    'Return only if the user selected a directory
    'BrowseInfo.ulFlags.struct = BIF.RETURNONLYFSDIRS
    BrowseInfo.ulFlags.struct = BIF.RETURNONLYFSDIRS or BIF.USENEWUI


    'Show the 'Browse for folder' dialog
    calldll #shell32, "SHBrowseForFolder",_
        BrowseInfo as struct,_
        lpIDList as long

    'return > 0 = success, so continue
    If lpIDList>0 Then
        'Set up a string buffer:
       sPath$ = space$(MAX.PATH) + chr$(0)
        'Get the path from the IDList
        calldll #shell32, "SHGetPathFromIDList",_
            lpIDList as long,_
            sPath$ as ptr,_
            r as long

This is what this piece of code produces on my computer.

        'The folder name is now in sPath$

        Open "ole32" for dll as #ole
        'Free the block of memory
        calldll #ole, "CoTaskMemFree",_
            lpIDList as long,_
            r as long
        close #ole

        'Check for null char, which
        'Signals end of folder name string
        iNull = InStr(sPath$, chr$(0))

        'Truncate string at null character
        If iNull Then
            sPath$ = Left$(sPath$, iNull - 1)
        End If
    End If

    DestinationPath$ = sPath$ 
    'If user cancelled, sPath$ is empty
    if DestinationPath$="" then wait
    print #main.textbox1, DestinationPath$

wait

'Now cause Explorer to open in that folder
call ShellExecute 0, sPath$,_SW_SHOWNA, "explore"

end

Sub ShellExecute hWnd, file$, parameter, lpszOp$
    ' _SW_SHOWNA      show normal
    ' _SW_HIDE        hide window
    ' _SW_MINIMIZE    minimize window
    ' lpszOp$ =  "open" or "print" or "explore"
    lpszFile$ = file$ 
    lpszDir$ = DefaultDir$ 
    lpszParams$=""
    CallDLL #shell32, "ShellExecuteA", hWnd As long,_
    lpszOp$ As ptr,lpszFile$ As ptr,_
    lpszParams$ As ptr,lpszDir$ As ptr,_
    parameter As long, result As long
    End Sub

wait
'-------------------------------------------------------------

The most important function of this simulator is the routine to find all files in a folder and to copy them. I used the MSDOS function XCOPY to do the same. XCOPY has some disadvantages. When it runs, it will show the black MSDOS window even if you use the @ECHO OFF batch statement. Of course HIDE WINDOW is a windows command that doesn't work in the MSDOS environment.

The function for finding files in folders is well documented. FileTree(MaxEntries,CurrentEntry,CurrentLevel,sPath$,txLen,Tree,Subdirs,SortKey)

You need to provide a maximum number of entries the routine will meet. In this case I used MaxEntries=1999 as Brad suggested that too in his example. I'll come back to this function again later on.

The screenshot above is just there to breakdown the text a little. It is a shot from some installer I wrote that uses Brad's routine too. This installer can be found in Newsletter #111

[button3Click]   'Perform action for the button named 'Start'

       sPath$ = DefaultDir$ + "\"  'change defaultdir (source dir) here
       #main.textbox1, "!hide"
       #main.graphbox1, "show"
       #main.groupbox2, "!hide"
       #main.groupbox3, "!show"

       Entries = FileTree(MaxEntries, 0, 0, sPath$, 24, 1, 1, 1)

After visiting the function we receive the number of entries and the accompanying file name for each entry. With this Entries I can calculate nlines to use in my graphical display.

  
 If Entries > 0 Then
           	 nlines = (graphw/Entries)
            		For x = 0 to Entries 		'-1     'just - 1 Brad? 
            		fName$ = FileTree$(x)
            		nName$ = DestinationPath$ + right$(fName$,len(fName$)-2)
            		tName$ = nName$

            			for t = 1 to len(tName$)
                    			if mid$(tName$,t,1) <> "\" then goto [nu]
                        		result = mkdir((left$(tName$,t)))
                                              'print result
                                              'result 5 means Drive exists
                                              'result 183 means Folder already exists
                                              'result 3 means ERROR
                                              'result 0 means Folder created

 [nu]          			next t

    cursor hourglass

'The last fName$ = "" so...

if fName$ = "" then nName$ = ""


    print #main.statictext6, nName$    
    print #main.statictext5, fName$    

Here comes the graphical calculation. A box of newx length is filled with the colour green every time a file is being copied.

            newx = nlines * x		 
            print #main.graphbox1, "backcolor green"
            print #main.graphbox1, "place 0 0"
            print #main.graphbox1, "down"
            print #main.graphbox1, "boxfilled ";newx;" 25"

    'API call to copy a file to a directory
    'This does the same as LB's command NAME 
    '-----------------------------------
    'Calldll #kernel32, "CopyFileA",_
    'fName$ as ptr,_
    'nName$ as ptr,_
    'bFailIfSucceed as long,_
    'ret as long
    '-----------------------------------

    		for TiMe = 1 to int(rnd(1)*1000) : next TiMe  'to simulate copy

    cursor normal

        	 Next x
    End If

    notice "Everything Installed"

    wait


'-------------------------------------------------------------

The next routine is from Brad Moore.

Thanks Brad. BTW shouldn't the x run to Entries - 1?

The last of the Entries is void.

Recursive function by Brad Moore

    'Arguments:
    '----------
    'MaxEntries is the maximum number of entries permitted in the array
    '   FileTree$(x).  It is the value of x, the size of array.
    'CurrentEntry is the current element in the array that was LAST
    '   populated.  It is used as a pointer to load the next array element.
    '   When the function is first called this value is zero.
    'CurrentLevel is the relative level in the directory structure
    '   that we are at compared with the original level called -
    '   this is always set to zero when the function is called.
    'Path$ is the directory path to the directory we are creating
    '   a tree for.
    'txLen is the value representing the number of MAX characters filename
    '   strings can hold.  The default (if zero is passed) is 15
    'Tree and Subdirs are both Boolean switches.  Set Tree = 1 if you
    '   want the function to traverse the whole directory tree (i.e. list
    '   all files in directory and subdirectories).  Any other value will
    '   disable this feature.
    '   Set Subdirs = 1 if you want the function to print subdirectry names
    '   along with the filenames.  Any other value will disable this feature.
    'SortKey is used to specify whether to sort files by name or size.  Set to
    '   value of 1 to sort by name, any other value will cause a sort by size.
    '
    'Return Value:
    '-------------
    'The function returns the latest entry that a value was written
    '   into.  If after calling the function it returns with zero you
    '   know that no files or subdirectories exist.


Function FileTree(MaxEntries,CurrentEntry,CurrentLevel,sPath$,txLen,Tree,Subdirs,SortKey)

    If txLen = 0 Then txLen = 15
    If sPath$ = "" or MaxEntries = 0 Then
       FileTree$(1) = "Error - Path is blank or MaxEntries = 0: Can't continue"
       CurrentEntry = 1
    Else

       If CurrentEntry + 1 < MaxEntries Then
          Files sPath$, "*.*", Finfo$()
          qtyFiles = Val(Finfo$(0, 0))
          qtySubDirs = Val(Finfo$(0, 1))

          'Now we will process the files on this level (of recursion)
          If qtyFiles > 0 Then

            For x =  qtyFiles to 1 step -1
               FileTree$(CurrentEntry) = sPath$ + Finfo$(x,0)
               'Insure there is room for the next entry
               totalBytes = totalBytes + val(Finfo$(x,1))
               CurrentEntry = CurrentEntry + 1
               If CurrentEntry >= MaxEntries Then Exit For
            Next x

         End If

         'Recurse any subdirectories if there are any and if Tree flag is set to one.
         If qtySubDirs > 0 and Tree = 1 Then
                x = 1
[FileTree.Loop]
                Files sPath$, "*.*", Finfo$()
                qtyFiles = Val(Finfo$(0, 0))
                qtySubDirs = Val(Finfo$(0, 1))

                If Right$(sPath$,1) <> "\" Then sPath$ = sPath$ + "\"
                NewPath$ = sPath$ + Finfo$(x+qtyFiles,1) + "\"

               'call FileTree recursively
                CurrentEntry = FileTree(MaxEntries, CurrentEntry, _
                                        CurrentLevel+1, NewPath$, txLen, Tree, Subdirs, SortKey)
               'Increment our counter that tracks which endicy we are on...
                x = x + 1
            If x <= qtySubDirs AND CurrentEntry+1 < MaxEntries Then GoTo [FileTree.Loop]
         End If
      End If
   End If

   FileTree = CurrentEntry

End Function


Home

Text To Speech - Pendl

Novice Puzzles - Terra

Slider Controls - Bradbury

Symmetrical Paint - Nally

Programming Style - Brossman

Progress Simulator - Rahman

CD Menus - Sweet

Media File Search - Sweet

Why Liberty BASIC? - Sweet

Submission Guildlines

Newsletter Help

Index